using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using XNAProject.GameElements;
using XNAProjectLibrary;
using XNAProject;
using XNAProject.Core;
using XNAProject.Ships;
using XNAProject.Enumerations;
using XNAProject.PathFinder;


namespace XNAProject.GameElements
{
    public class Level : Microsoft.Xna.Framework.DrawableGameComponent
    {
        #region Fields

        public Hexagon[,] hexagonCollection { get; set; }
        private Plane levelPlane;
        private Ocean ocean;

        public Vector2 size { get; set; } 
        public Vector2 selected { get; set; }
        public Vector2 targeted { get; set; }
        public Vector2 highlightedHexagon { get; set; }
        private List<Vector2> path;

        private IInputHandler Input;
        private Player player;
        private Enemy enemy;
        private IPathFinder PathFinder;

        public bool active { get; set; }       

        #region LevelDetails

        private string name;
        private int maxPlayer;
        public int money { get; set; }
        public TimeSpan TurnTime { get; set; }

        private LevelSizeType levelSizeType;
        private LevelMapType levelMapType;
        #endregion

        #endregion

        public Level(Game game, LevelSizeType LevelSize, int levelMoney): base(game)
        {
            Game.Services.AddService(typeof(Level), this);
            PathFinder = new XNAProject.PathFinder.PathFinder(game);
            Game.Services.AddService(typeof(IPathFinder), PathFinder);
            XNAProjectCamera camera = (XNAProjectCamera)Game.Services.GetService(typeof(XNAProjectCamera));
            GameComponentCollection componentCollection = (GameComponentCollection)Game.Services.GetService(typeof(GameComponentCollection));
            enemy = (Enemy)Game.Services.GetService(typeof(Enemy));
            player = (Player)Game.Services.GetService(typeof(Player));
            Input = (IInputHandler)Game.Services.GetService(typeof(IInputHandler));

            TurnTime = new TimeSpan(0, 0, 100);
            active = false;

            levelSizeType = LevelSize;
            money = levelMoney;
            size = new Vector2(45, 20);
            selected = new Vector2();
            targeted = new Vector2();
            highlightedHexagon = new Vector2();

            hexagonCollection = new Hexagon[(int)size.X, (int)size.Y];
            levelPlane = new Plane(new Vector3(0f, 1f, 0f), 0f);

            Random rand = new Random();

            //add hexagons to level based on size
            for (int j = 0; j < size.Y; j++)
            {
                for (int i = 0; i < size.X; i++)
                {
                    hexagonCollection[i, j] = new Hexagon(Game, new Vector2(i, j), new Vector2(0, 0), true, false, rand.Next(200), rand.Next(200), rand.Next(200));
                    componentCollection.Add(hexagonCollection[i, j]);
                }
            }  

            ocean = new Ocean(Game, "Effects/Ocean", "Models/Level/ocean", "OceanEffect", "Textures/Level/water",
                "Textures/Level/wavesbump", "Textures/Level/sky_dome2", 150f, new Vector3(1.57f, 0, 0), 
                new Vector3(3000, 0, 500), 1.0f, new Vector4(1.0f, 0f, -2.5f, 1.0f));
            //componentCollection.Add(ocean);
        }

        public override void Update(GameTime gameTime)
        {
            XNAProjectCamera camera = (XNAProjectCamera)Game.Services.GetService(typeof(XNAProjectCamera));
            
            //Just for Debug purposes
            #region Oil

            if (Input.WasPressed(0, Buttons.LeftShoulder, Keys.O))
            {
                if (this[selected].oilSpill == false)
                    this[selected].oilSpill = true;
                else this[selected].oilSpill = false;
            }

            #endregion

            #region Cursor

            double denominator = Vector3.Dot(levelPlane.Normal, Input.CursorDirection(camera.Projection, camera.View));
            double numerator = Vector3.Dot(levelPlane.Normal, Input.CursorRay(camera.Projection, camera.View).Position) + levelPlane.D;
            double t = -(numerator / denominator);

            //a point on the hexagon plane
            Vector3 pickedPosition = Input.NearPoint(camera.Projection, camera.View) + Input.CursorDirection(camera.Projection, camera.View) * (float)t;
            
            if (pickedPosition.X > 0 && pickedPosition.Z > 0)
            {
                //hexagon estimated index in the hexagon array
                Vector2 picked = new Vector2((float)Math.Round(pickedPosition.X / hexagonCollection[0, 0].Width),
                    (float)Math.Round(pickedPosition.Z / hexagonCollection[0, 0].Height) - 1);

                if (picked.X % 2 == 0)
                {
                    //shift down if needed
                    picked = new Vector2((float)Math.Round(pickedPosition.X / hexagonCollection[0, 0].Width),
                    (float)Math.Round((pickedPosition.Z + (hexagonCollection[0, 0].Height / 2)) / hexagonCollection[0, 0].Height) - 1);
                }                

                if (picked.X >= 0 && picked.X < size.X   //Making shure picked is in Range
                    && picked.Y >= 0 && picked.Y < size.Y)
                {
                    #region Intersection Check

                    List<Vector2> temp = this[picked].GetAreaAroundSelf(1);
                    Ray ray = Input.CursorRay(camera.Projection, camera.View);
                    for (int i = 0; i < temp.Count; i++)
                    {
                        if (this[temp[i]].Intersect(ray))
                            picked = temp[i];
                    }

                    #endregion

                    #region Highlight

                    this[highlightedHexagon].UnHighlight();
                    
                    highlightedHexagon = new Vector2(picked.X, picked.Y);

                    if (highlightedHexagon.Y > size.Y) highlightedHexagon = new Vector2(highlightedHexagon.X, highlightedHexagon.Y - 1);
                    if (highlightedHexagon.Y < 0) highlightedHexagon = new Vector2(highlightedHexagon.X, 0);

                    this[highlightedHexagon].Highlight();

                    #endregion

                    if (active)
                    {
                        #region Select

                        if (Input.MouseLeftClicked())
                        {
                            Select(highlightedHexagon);
                        }

                        #endregion

                        #region Action

                        if (Input.MouseRightClicked() &&
                            this[selected].ship != null &&
                            player.OwnFleet.shipCollection.Contains(this[selected].ship))
                        {
                            if (player.turn)
                            {
                                #region First Click

                                if (highlightedHexagon != targeted)
                                {
                                    this[targeted].UnTarget();

                                    targeted = highlightedHexagon;

                                    if (this[targeted].ship != null &&
                                        this[targeted].ship != this[selected].ship &&
                                        this[targeted].ship.visible &&
                                        enemy.OwnFleet.shipCollection.Contains(this[targeted].ship))
                                    {
                                        //Attack
                                        if (path != null) EndWaypoint();
                                        this[targeted].AttackTarget();
                                        this[selected].ship.Attack(targeted);
                                    }
                                    else if (!this[targeted].oilSpill && this[targeted].discovered)
                                    {
                                        //Move
                                        this[selected].ship.Move(targeted);
                                    }
                                }

                                #endregion

                                #region Second Click

                                else
                                {
                                    if (this[targeted].ship != null &&
                                        this[targeted].ship.visible &&
                                        this[targeted].discovered)
                                    {
                                        //ATTACK!
                                    }
                                    else if (!this[targeted].oilSpill && this[targeted].discovered)
                                    {
                                        this[selected].ship.ActuallyMove();
                                    }
                                }

                                #endregion
                            }
                            else //If not player's turn Action Console 
                            {
                                ConsoleMenu console = (ConsoleMenu)Game.Services.GetService(typeof(ConsoleMenu));
                                console.ActionText("Not your Turn!");
                            }
                        }

                        #endregion
                    }
                }
            }

            #endregion
        }

        public void Select(Vector2 Position)
        {
            this[selected].UnSelect();
            if (path != null) EndWaypoint();

            selected = Position;

            this[selected].Select();
            this[targeted].UnTarget();
        }

        #region WayPoint on/off

        public void DrawWaypoint(List<Vector2> way)
        {
            path = way;
            foreach (Vector2 point in way)
            {
                if (way.IndexOf(point) != 0)
                    this[point].Waypoint();
            }
        }

        public void EndWaypoint()
        {
            if (path != null)
            {
                foreach (Vector2 point in path)
                {
                    if (path.IndexOf(point) != 0)
                        this[point].EndWaypoint();
                }
                path = null;
            }
        }

        #endregion

        #region Helpers

        public Hexagon this[Vector2 coordinates]
        //indexer for easier access
        {
            get
            {
                return hexagonCollection[(int)coordinates.X, (int)coordinates.Y];
            }
            set
            {
                hexagonCollection[(int)coordinates.X, (int)coordinates.Y] = value;
            }
        }

        public Hexagon this[int x, int y]
        //indexer for easier access
        {
            get
            {
                return hexagonCollection[x, y];
            }
            set
            {
                hexagonCollection[x, y] = value;
            }
        }

        #endregion
    }
}